package top.ivansong92.example.leetcode.learning.data.struct.array.extension.queue;


import java.math.BigDecimal;

public class NewLoopQueue<E> implements NewQueue<E> {

    public E[] data;
    public int head, tail;
    public int size;
    private double ENCAPTITY = 1.5D;

    public NewLoopQueue(int captity) {
        if (captity <= 0) {
            throw new IllegalArgumentException("captity is illegal");
        }
        data = (E[]) new Object[captity];
        head = 0;
        tail = 0;
        size = 0;
    }

    public NewLoopQueue() {
        this(16);
    }

    @Override
    public void enqueue(E e) {
        if (size == Integer.MAX_VALUE) {
            throw new RuntimeException("queue is full");
        }

        int len = data.length;
        if (size == len) {
            int newLen = (int) Math.min(new BigDecimal(len).multiply(new BigDecimal(ENCAPTITY)).longValue(), (long)Integer.MAX_VALUE);
            resize(newLen);
        }

        data[tail] = e;
        tail = Math.max(0, (tail + 1) % data.length);
        size ++;
    }

    @Override
    public E dequeue() {
        if (isEmpty()) {
            throw new RuntimeException("queue is empty");
        }
        E e = data[head];
        data[head] = null;
        head = Math.max(0, (head + 1) % data.length);
        size --;
        if (size != 0 && data.length / size == 4) {
            resize(data.length / 2);
        }
        return e;
    }


    @Override
    public E getHeader() {
        if (size() == 0) {
            return null;
        }
        return data[head];
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public String toString() {
        String[] dataStrings = new String[size()];
        if (dataStrings.length > 0) {
            int j = 0;
            if (tail <= head) {
                for(int i = head; i < data.length; i ++) {
                    dataStrings[j] = data[i].toString();
                    j ++;
                }
                for(int i = 0; i < tail; i ++) {
                    dataStrings[j] = data[i].toString();
                    j ++;
                }
            } else {
                for(int i = head; i < tail; i ++) {
                    dataStrings[j] = data[i].toString();
                    j ++;
                }
            }
        }


        return "Queue:[head,...,trail],size:"+ size +"([" + String.join(",", dataStrings) + "])";
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }


    private void resize(int newSize) {
        E[] newData = (E[]) new Object[newSize];
        int j = 0;
        if (tail <= head) {
            for(int i = head; i < data.length; i ++) {
                newData[j] = data[i];
                j ++;
            }
            for(int i = 0; i < tail; i ++) {
                newData[j] = data[i];
                j ++;
            }
        } else {
            for(int i = head; i < tail; i ++) {
                newData[j] = data[i];
                j ++;
            }
        }
        head = 0;
        tail = j;
        data = newData;
    }
    static int MAXIMUM_CAPACITY = 1 << 30;
    public static void main(String[] args) {
        System.out.println(Runtime.getRuntime().freeMemory());
        System.out.println(Runtime.getRuntime().totalMemory());
//        NewLoopQueue<String> queue = new NewLoopQueue<>(Integer.MAX_VALUE - 2);
//        queue.size = 2;
//        queue.head = Integer.MAX_VALUE - 3;
//        queue.tail = 1;
//        queue.data[Integer.MAX_VALUE - 3] = "1";
//        queue.data[0] = "2";
//        System.out.println(queue);
        //Object[] objects = new Object[Integer.MAX_VALUE];


//        System.out.println((1 << 30) - 1);
//        System.out.println(((1 << 30) -1) << 1);
//        System.out.println(Integer.MAX_VALUE);

        int oldCap = MAXIMUM_CAPACITY - 2;
        int newCap = 0;
        int threshold = 0;
        int newThr = 0;
        int oldThr = 12033;
        int DEFAULT_INITIAL_CAPACITY = 1 << 4;
        if (oldCap > 0) {
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;

            }
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                    oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold
        }

        System.out.println(newCap);
        System.out.println(newThr);
        System.out.println(Integer.MAX_VALUE);
        System.out.println(MAXIMUM_CAPACITY);
        System.out.println(tableSizeFor(oldCap));
        System.out.println(tableSizeFor(1024));
        System.out.println(tableSizeFor(8));
    }

    static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }
}
